package com.zisu.secs.secs.secs2;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

public class Secs2BytesParser {
	
	private Secs2BytesParser() {
	}
	
	private static class SingletonHolder {
		private static final Secs2BytesParser inst = new Secs2BytesParser();
	}
	
	public static Secs2BytesParser getInstance() {
		return SingletonHolder.inst;
	}
	
	public Secs2 parse(List<ByteBuffer> buffers) throws Secs2BytesParseException {
		
		if ( hasRemaining(buffers) ) {
			
			Secs2 ss = stpParse(buffers);
			
			if ( hasRemaining(buffers) ) {
				throw new Secs2BytesParseException("not reach end buffers");
			}
			
			return ss;
			
		} else {
			
			return new Secs2RawBytes();
		}
	}
	
	private static Secs2 stpParse(List<ByteBuffer> buffers) throws Secs2BytesParseException {
		//先获取 第一个字节 ，第一个字节 包含了  Data Item Type + Number of length bytes
		byte b = get(buffers);

		//获取这个数据 的类型（如，list ascii 或者binary ...）
		Secs2Item s2i = Secs2Item.get(b);
		//获取length ，就是 length byte  就是 说有  secs 里面几项（几个字节存储）
		int lengthBits = b & 0x03;
		//size
		// 	 	① 如果是list 就代表 这个secs message 下面有几项数据
		//      ② 如果非list 就代表 是一个元素，并且size 就是这个元素占用几个字节来表达。
		int size = 0;

		//一共就3种可能 0字节就不处理了（因为一共就2bit 总共就能表示4种可能）
		//如果3个字节来存储（secs 里面的几项数据 ，就是这个secs 里面包含了几个数据（看Guide_to_under...  第9页））
		if ( lengthBits == 3 ) {
			
			size =  ((int)(get(buffers)) << 16) & 0x00FF0000;
			size |= ((int)(get(buffers)) <<  8) & 0x0000FF00;
			size |= ((int)(get(buffers))      ) & 0x000000FF;
			
		}
		// 如果两个字节
		else if ( lengthBits == 2 ) {
			//get(buffers)是获取一个字节的
			//获取字节1
			size =  ((int)(get(buffers)) <<  8) & 0x0000FF00;
			//获取字节2   |=  就相当于   高位字节 +  低位字节 =  总数
			size |= ((int)(get(buffers))      ) & 0x000000FF;
			
		}
		//如果1个字节
		else if ( lengthBits == 1 ) {
			size =  ((int)(get(buffers))      ) & 0x000000FF;
		}
		
		if ( s2i == Secs2Item.LIST ) {
			
			List<Secs2> ll = new ArrayList<>();
			
			for (int i = 0 ; i < size ; ++i) {
				//回调  再去解析 这个 byte
				ll.add(stpParse(buffers));
			}
			
			return new Secs2List(ll);
			
		}
		// 如果不是list ，那么就说明 secs 就只有一个元素
		else {
			
			byte[] bs = get(buffers, size);
			
			switch ( s2i ) {
			case ASCII: {
				return new Secs2Ascii(bs);
				/* break */
			}
			case BINARY: {
				return new Secs2Binary(bs);
				/* break */
			}
			case BOOLEAN: {
				return new Secs2Boolean(bs);
				/* break */
			}
			case INT1: {
				return new Secs2Int1(bs);
				/* break */
			}
			case INT2: {
				return new Secs2Int2(bs);
				/* break */
			}
			case INT4: {
				return new Secs2Int4(bs);
				/* break */
			}
			case INT8: {
				return new Secs2Int8(bs);
				/* break */
			}
			case UINT1: {
				return new Secs2Uint1(bs);
				/* break */
			}
			case UINT2: {
				return new Secs2Uint2(bs);
				/* break */
			}
			case UINT4: {
				return new Secs2Uint4(bs);
				/* break */
			}
			case UINT8: {
				return new Secs2Uint8(bs);
				/* break */
			}
			case FLOAT4: {
				return new Secs2Float4(bs);
				/* break */
			}
			case FLOAT8: {
				return new Secs2Float8(bs);
				/* break */
			}
			case JIS8: {
				return new Secs2Jis8(bs);
				/* break */
			}
			case UNICODE: {
				return new Secs2Unicode(bs);
				/* break */
			}
			default: {
				throw new Secs2UnsupportedDataFormatException();
			}
			}
		}
	}
	
	private static boolean hasRemaining(List<ByteBuffer> buffers) {
		return buffers.stream().anyMatch(ByteBuffer::hasRemaining);
	}
	
	private static byte get(List<ByteBuffer> buffers) throws Secs2BytesParseException {
		//buffers 是存储的 整个数据块 （一个小块是1M ）
		for ( ByteBuffer bf : buffers ) {
			if ( bf.hasRemaining() ) {
				//一个字节一个字节取
				return bf.get();
			}
		}
		throw new Secs2BytesParseException("reach end buffers");
	}
	
	private static byte[] get(List<ByteBuffer> buffers, int size) throws Secs2BytesParseException {
		byte[] bs = new byte[size];
		for (int i = 0; i < size; ++i) {
			bs[i] = get(buffers);
		}
		return bs;
	}
	
}
